package com.apps.saspect.impl;


import com.apps.sannotation.keys.TimeLockKey;
import com.apps.saspect.CallTimeLock;
import com.apps.saspect.model.vo.KeyValueVo;
import com.apps.saspect.utils.AspectUtils;
import com.apps.sconfig.SDevFastConfig;
import com.apps.sconfig.enums.LockType;
import com.apps.sexctption.LockException;
import com.apps.sexctption.NullException;
import com.apps.stoolkit.RedissonToolkit;
import com.apps.stoolkit.SpiderLockToolkit;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;

@Slf4j
@Aspect
@Component
@Configuration
public class CallTimeLockAspect {


    @Autowired(required = false)
    private SDevFastConfig sDevFastConfig;

    //锁前缀
    private String prifix="CallTimeLockAspect_";


    @Pointcut("@annotation(com.apps.saspect.CallTimeLock)")
    public void pointcut() {

    }

    @Before("pointcut()")
    public void doBefore(JoinPoint joinPoint) throws InterruptedException {

        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        CallTimeLock callTimeLock =method.getDeclaredAnnotation(CallTimeLock.class);
        if(null == callTimeLock)
            throw new NullException("没有找到@CallTimeLock注解");
        String keys =prifix + joinPoint.getTarget().getClass().getSimpleName()+"_"+method.getName() + "_";
        List<KeyValueVo> params= AspectUtils.handlerParameter(joinPoint, TimeLockKey.class); //获取方法的参数传值
        //用参数拼装key
        keys += AspectUtils.generateKey(params);
        if(sDevFastConfig.getLockType() == LockType.LOCAL) {
            if(!SpiderLockToolkit.tryLock(keys,0L, callTimeLock.seconed(), callTimeLock.unit()))
                throw new LockException(callTimeLock.errMsg());
        }else if(sDevFastConfig.getLockType() == LockType.REDISSON)
        {
            RLock lock = RedissonToolkit.getRLock(keys);
            boolean bs = lock.tryLock(0, callTimeLock.seconed(), callTimeLock.unit());
            if (!bs)
                throw new LockException(callTimeLock.errMsg());
        }
    }

}
